<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>{{ supportMsg }}</h2>
    房间号:
    <input v-model="roomID" />
    <br />
    推流id:
    <input v-model="publishStreamID" />
    <!-- 媒体节点:
    <input v-model="mediaNode" /> -->
    推流转推地址:
    <input v-model="publishURL" />
    主播拉流id:
    <input v-model="playerID" />
    <br />
    观众拉流id-1:
    <input v-model="playerID1" />
    观众拉流id-2:
    <input v-model="playerID2" />
    <br />
    观众拉流地址1:
    <input v-model="playerURL1" />
    观众拉流地址2:
    <input v-model="playerURL2" />
    <br />
    混流输入ids(逗号隔开):
    <input v-model="mixStreamInputs" />
    混流cdn地址:
    <input v-model="mixStreamOutPut" />
    <div class="playerID">
      摄像头:
      <select v-model="videoInput">
        <option
          v-for="item in cameras"
          :key="item.deviceID"
          :value="item.deviceID"
        >
          {{ item.deviceName }}
        </option>
      </select>
      麦克风:
      <select v-model="audioInput">
        <option
          v-for="item in microphones"
          :key="item.deviceID"
          :value="item.deviceID"
        >
          {{ item.deviceName }}
        </option>
      </select>

      <input type="file" @change="pickAudio($event)" />
      <br />
      <br />
      <button @click="publish">推流(有cdn地址默认转推)</button>
      <button @click="stopCDNPublish">停止cdn地址转推</button>
      <button @click="loadBGMusic">主播加载背景音乐</button>
      <button @click="pull(1)">观众cdn拉流</button>
      <button @click="pull(2)">观众服务器拉流</button>
      <button @click="hostPullByID()">主播指定id拉流</button>
      <button @click="mixStream()">主播发起混流</button>
      <button @click="stopMixStream()">主播停止混流</button>
      <button @click="stop()">停止</button>
    </div>
    <div>
      <audio controls :src="bgMusic" ref="bgAudio"></audio>
      <video autoplay muted :srcObject.prop="localStream"></video>
    </div>
    <div class="play">
      <video
        v-for="play in playList"
        :key="play.streamID"
        :ref="play.streamID"
        controls
        autoplay
      ></video>
    </div>
  </div>
</template>

<script>
import { ZegoExpressEngine } from "zego-express-engine-webrtc";
import { getBrowser, isAndroidWeChat } from "../assets/util";
import axios from "axios";
import flvjs from "flv.js";
import md5 from "md5";

let zg;
const APPID = 977747743,
  SERVER = "wss://webliveroom-test.zego.im/ws",
  TOKENSERVER = "https://wsliveroom-alpha.zego.im:8282/token",
  APPSECRET = "bf971b5f48909f55a2a824bd530a040e";
// CDNURL =
//   "rtmp://livepush.17kuxiu.com/live/30310_888888889091?txSecret=2bceb251722976a562c552cda9cd47e2&txTime=5E8DF4FF",
// PLAYCDNURL = "http://newlive.17kuxiu.com/live/30310_888888889091.flv";

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      supportMsg: "检测中....",
      microphones: [],
      cameras: [],
      localStream: null,
      roomID: "666",
      userID: "u" + new Date().getTime(),
      videoInput: null,
      audioInput: null,
      publishStreamID: "host" + new Date().getTime(),
      bgMusic: null,
      publishSuc: false,
      playType: 1,
      playList: [],
      playerID: 0,
      playerID1: 0,
      playerID2: 0,
      playerURL1: "",
      playerURL2: "",
      logined: false,
      publishURL: "",
      mixStreamInputs: "",
      mixStreamOutPut: "",
      taskID: "",
      mediaNode:''
    };
  },
  async mounted() {
    // 初始化sdk
    zg = new ZegoExpressEngine(APPID, SERVER);
    console.log("zg", zg);

    // 检测支持度
    const support = await zg.checkSystemRequirements();
    this.supportMsg = `支持度检测结果:
       webRTC:${support.webRTC ? "支持" : "不支持"},
       自定义推流:${support.customCapture ? "支持" : "不支持"},
         摄像头:${support.camera ? "支持" : "不支持"},
          麦克风:${support.microphone ? "支持" : "不支持"},
           H264视频编码:${support.videoCodec.H264 ? "支持" : "不支持"},
           VP8视频编码:${support.videoCodec.H264 ? "支持" : "不支持"},
       `;

    // 获取摄像头麦克风设备
    const { microphones, cameras } = await zg.enumDevices();
    this.cameras = cameras;
    this.microphones = microphones;
    this.audioInput = this.microphones[0].deviceID;
    this.videoInput = this.cameras[0].deviceID;

    // 回调事件监听

    zg.on("roomStateUpdate", (roomID, state, errorCode, extendedData) => {
      // 添加自己的错吴逻辑
      console.warn(
        "roomStateUpdate callBack:",
        roomID,
        state,
        errorCode,
        extendedData
      );
    });

    zg.on("publisherStateUpdate", result => {
      console.warn(
        "publisherStateUpdate callBack:",
        result.streamID,
        result.state
      );
      // 推流成功
      if (result.state === "PUBLISHING") {
        this.publishSuc = true;
        const signature = md5(
          APPID + "" + Math.ceil(new Date().getTime() / 1000) + APPSECRET
        );
        this.publishURL &&
          zg.addPublishCdnUrl(this.publishStreamID, signature, this.publishURL);
      } else if (result.state === "NO_PUBLISH") {
        // todo: 重试或者提示客户失败
        // 可能的原因: 1防火墙被关闭  2: 网络中间断开,且超过重连时间
      }
    });
    //
    zg.on("publishQualityUpdate", (streamID, stats) => {
      console.warn(
        "publishQualityUpdate callBack:",
        streamID,
        JSON.stringify(stats)
      );
    });
    zg.on("playerStateUpdate", result => {
      if (result.state === "NO_PLAY") {
        // todo: 重试或者提示客户失败
        // 可能的原因: 1防火墙被关闭  2: 网络中间断开,且超过重连时间
      }
    });
  },
  methods: {
    async login() {
      if (!zg) {
        alert("初始化sdk失败");
        return;
      }
      // 登录
      const { data: token } = await axios.get(
        TOKENSERVER + `?app_id=${APPID}&id_name=${this.userID}`
      );
      const loginRes = await zg.loginRoom(this.roomID, token, {
        userID: this.userID,
        userName: this.userID.replace("u", "name")
      });
      this.logined = true;
      return loginRes;
    },
    async publish() {
        if(this.mediaNode){
          zg.setCustomSignalUrl(this.mediaNode)
        }

      // 创建本地推流,view层渲染
      this.localStream = await zg.createStream({
        camera: {
          audioInput: this.audioInput,
          videoInput: this.videoInput,
          videoQuality: 4,
          // horizontal: true
          width: 640,
          height: 480,
          frameRate: 20,
          bitRate: 1500
        }
      });

      // 登录
      const loginRes = await this.login();

      if (!loginRes) {
        alert("登录失败,请检查网络是否畅通");
        return;
      }

      // 推流
      zg.startPublishingStream(this.publishStreamID, this.localStream);
    },
    stopCDNPublish() {
      const signature = md5(
        APPID + "" + Math.ceil(new Date().getTime() / 1000) + APPSECRET
      );
      this.publishURL &&
        zg.removePublishCdnUrl(
          this.publishStreamID,
          signature,
          this.publishURL
        );
    },
    pickAudio(event) {
      console.warn("event", event);
      const file = event.target.files[0];
      const url = window.URL.createObjectURL(file);
      console.warn("url", url);
      this.bgMusic = url;
    },
    loadBGMusic() {
      if (this.publishSuc) {
        zg.startMixingAudio(this.publishStreamID, this.$refs.bgAudio, false);
      }
    },
    async hostPullByID() {
      this.playType = 2;
      this.playerID &&
        this.playList.push({
          streamID: this.playerID
        }) &&
        this.$nextTick(() => {
          this.pullByID(this.playerID);
        });
    },
    async pull(type) {
      await this.login();
      this.playType = type;
      if (type === 1) {
        if (this.playerURL1) {
          const stream = {
            streamID: "RL1" + new Date().getTime(),
            urlsHttpsHLS: [this.playerURL1],
            urlsHttpsFLV: [this.playerURL1]
          };
          this.playList.push(stream);
          this.$nextTick(() => {
            this.pullByURL(stream);
          });
        }

        if (this.playerURL2) {
          const stream = {
            streamID: "RL2" + new Date().getTime(),
            urlsHttpsHLS: [this.playerURL2],
            urlsHttpsFLV: [this.playerURL2]
          };
          this.playList.push(stream);
          this.$nextTick(() => {
            this.pullByURL(stream);
          });
        }
      } else if (type === 2) {
        this.playerID1 &&
          this.playList.push({
            streamID: this.playerID1
          }) &&
          this.$nextTick(() => {
            this.pullByID(this.playerID1);
          });
        this.playerID2 &&
          this.playList.push({
            streamID: this.playerID2
          }) &&
          this.$nextTick(() => {
            //setTimeout(() => {
            this.pullByID(this.playerID2);
            //}, 2000);
          });
      }
    },
    async pullByID(playerID) {
      console.warn("playerID", playerID);
      const remoteStream = await zg.startPlayingStream(playerID);
      const targetVideo = this.$refs[playerID][0];
      console.warn("targetVideo", targetVideo);
      targetVideo.srcObject = remoteStream;
    },
    pullByURL(stream) {
      const targetVideo = this.$refs[stream.streamID][0];
      if (!targetVideo) {
        alert("拉流video还不存在");
        return;
      }
      // hls
      if (getBrowser() === "Safari" && !isAndroidWeChat()) {
        const urlsHttpsHLS = stream.urlsHttpsHLS;
        urlsHttpsHLS && urlsHttpsHLS[0] && (targetVideo.src = urlsHttpsHLS[0]);
      } else if (flvjs.isSupported()) {
        //若支持flv.js
        const urlsHttpsFLV = stream.urlsHttpsFLV;
        if (urlsHttpsFLV && urlsHttpsFLV[0]) {
          const flvPlayer = flvjs.createPlayer(
            {
              type: "flv",
              isLive: true,
              url: urlsHttpsFLV[0],
              hasAudio: true
            },
            {
              stashInitialSize: 1800,
              enableStashBuffer: false,
              autoCleanupSourceBuffer: true,
              reuseRedirectedURL: true
            }
          );
          flvPlayer.on(flvjs.Events.LOADING_COMPLETE, () => {
            flvPlayer.play();
          });
          flvPlayer.on(flvjs.Events.ERROR, (...param) => {
            console.error("ERROR", param);
            if (param && param[2] && param[2].code === 11) {
              stream.player.unload();
              stream.player.detachMediaElement();
              stream.player.destroy();
              this.pullByURL(stream);
            }
          });
          flvPlayer.attachMediaElement(targetVideo);
          flvPlayer.load();
          targetVideo.muted = false;
          stream.player = flvPlayer;
        } else {
          alert("请确认配置了cdn");
        }
      }
    },
    async mixStream() {
      //this.stopCDNPublish();
      if (this.mixStreamInputs) {
        const [streamID1, streamID2] = this.mixStreamInputs.split(",");
        let streamList = [
          {
            streamID: streamID1,
            layout: {
              top: 0,
              left: 0,
              bottom: 480,
              right: 320
            }
          },
          {
            streamID: streamID2,
            layout: {
              top: 0,
              left: 320,
              bottom: 480,
              right: 640
            }
          }
        ];
        if (streamID1 && !streamID2) {
          streamList = [
            {
              streamID: streamID1,
              layout: {
                top: 0,
                left: 0,
                bottom: 480,
                right: 640
              }
            }
          ];
        }

        !this.taskID && (this.taskID = "mix-task-" + new Date().getTime());
        const result = await zg.startMixerTask({
          taskID: this.taskID,
          inputList: streamList,
          outputList: [this.mixStreamOutPut],
          outputConfig: {
            outputBitrate: 1500,
            outputFps: 15,
            outputWidth: 640,
            outputHeight: 480,
            singleStreamPassThrough: true
          }
        });
        //  alert("混流结果" + JSON.stringify(result));
        console.warn("startMixerTask", result);
      }
    },
    stopMixStream() {
      zg.stopMixerTask(this.taskID);
      this.taskID = "";
    },
    stopPlay(stream) {
      if (this.playType === 1) {
        if (stream.player) {
          stream.player.pause();
          stream.player.unload();
          stream.player.detachMediaElement();
          stream.player.destroy();
          stream.player = null;
        }
      } else {
        zg.stopPlayingStream(stream.streamID);
      }
    },
    stop() {
      if (zg) {
        if (this.publishSuc) {
          zg.stopPublishingStream(this.publishStreamID);
          zg.destroyStream(this.localStream);
        }
        if (this.playList && this.playList.length > 0) {
          this.playList.forEach(item => {
            this.stopPlay(item);
          });
        }
        if (this.taskID) this.stopMixStream();
        this.playList = [];
        setTimeout(() => {
          zg.logoutRoom(this.roomID);
        }, 1000);
      }
    }
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
